﻿
using Stardust.Common.Enum;
using Stardust.Common.Model;
using Stardust.Common.Utils;
using Stardust.ConfigCenterWeb.Code.Entities;
using Stardust.ConfigCenterWeb.Code.Repositories;
using Stardust.ConfigCenterWeb.Code.Repositories.Impl;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Stardust.ConfigCenterWeb.Code.Services
{
    public class ServerNodeService
    {
        public static ServerNodeService Instance = new ServerNodeService();

        IServerNodeRepository serverNodeRepository = new ServerNodeRepository();
        INodeEventRepository nodeEventRepository = new NodeEventRepository();
        object _lockObj;
        public ServerNodeService()
        {
            _lockObj = new object();
        }


        /// <summary>
        /// 根据服务名获取服务节点
        /// </summary>
        /// <param name="serviceName"></param>
        /// <returns></returns>
        public List<ServerNode> GetNodesByName(string serviceName)
        {
            lock (_lockObj)
            {
                var list = serverNodeRepository.SearchList(serviceName, null, null, ServerNodeStatus.Normal);
                return list;
            }
        }

        public List<ServerNode> SearchList(string serviceName, string address, string version, ServerNodeStatus? status)
        {
            lock (_lockObj)
            {
                return serverNodeRepository.SearchList(serviceName, address, version, status);
            }
        }

        /// <summary>
        /// 获取需要配置中心主动监测的节点
        /// </summary>
        /// <returns></returns>
        public void CheckAliveJob()
        {
            var list = serverNodeRepository.GetCheckAliveNodes();
            if (list.Count > 0)
            {
                list.ForEach(node =>
                {
                    HttpHelper.GetStringFromUrlAsync(node.GetStardustUrl("/__Internal/CheckAlive"), 8000).ContinueWith(task =>
                    {
                        if (task.IsFaulted)
                        {
                            Logout(node.Id, node.ServiceName);
                        }
                        else
                        {
                            if ("1".Equals(task.Result))
                            {
                                Heartbeat(node.Id);
                            }
                            else
                            {
                                Logout(node.Id, node.ServiceName);
                            }
                        }
                    });
                });
            }

        }

        public void CheckRegisterJob()
        {
            var list = serverNodeRepository.GetCheckRegisterNodes();
            if (list.Count > 0)
            {
                list.ForEach(CheckOneRegister);
            }
        }
        private void CheckOneRegister(ServerNode node)
        {
            HttpHelper.GetStringFromUrlAsync(node.GetStardustUrl(), 8000).ContinueWith(task =>
            {
                if (task.IsFaulted)
                {
                    var exp = task.Exception.GetBaseException();
                }
                else
                {
                    Register(node);
                }
            });
        }

        /// <summary>
        /// 注册服务
        /// </summary>
        /// <param name="m"></param>
        /// <returns></returns>
        public ServerNode Register(ServerNode m)
        {
            m.Status = ServerNodeStatus.Normal;
            m.HeartbeatTime = DateTime.Now;
            lock (_lockObj)
            {
                var node = serverNodeRepository.GetNodeByName(m.ServiceName, m.Address);
                var flag = 0L;
                if (node == null)
                {
                    flag = serverNodeRepository.Add(m);
                    m.Id = flag;
                }
                else
                {
                    m.Id = node.Id;
                    m.Weight = node.Weight;
                    m.Version = node.Version;
                    flag = serverNodeRepository.Update(m);
                }
                if (flag > 0)
                {
                    NodeEvent ev = new NodeEvent
                    {
                        EventType = NodeEventType.Register,
                        ServerNodeId = m.Id,
                        TriggerTime = DateTime.Now,
                        ServiceName = m.ServiceName,
                    };
                    nodeEventRepository.Add(ev);
                    return m;
                }
                else
                {
                    return null;
                }
            }
        }

        public void Edit(ServerNode m)
        {
            lock (_lockObj)
            {
                if (m.Id > 0)
                {
                    var flag = serverNodeRepository.Update(m);
                    NodeEvent ev = new NodeEvent
                    {
                        EventType = NodeEventType.Update,
                        ServerNodeId = m.Id,
                        TriggerTime = DateTime.Now,
                        ServiceName = m.ServiceName,
                    };
                    nodeEventRepository.Add(ev);
                }
                else
                {
                    var node = serverNodeRepository.GetNodeByName(m.ServiceName, m.Address);
                    if (node != null)
                    {
                        node.Version = m.Version;
                        node.Weight = m.Weight;
                        var flag = serverNodeRepository.Update(node);
                        NodeEvent ev = new NodeEvent
                        {
                            EventType = NodeEventType.Update,
                            ServerNodeId = node.Id,
                            TriggerTime = DateTime.Now,
                            ServiceName = m.ServiceName,
                        };
                        nodeEventRepository.Add(ev);
                        CheckOneRegister(node);
                    }
                    else
                    {
                        m.Status = ServerNodeStatus.Disconnect;
                        var flag = serverNodeRepository.Add(m);
                        CheckOneRegister(m);
                    }
                }
            }
        }

        public void Delete(long nodeId, string serviceName)
        {
            lock (_lockObj)
            {
                var flag = serverNodeRepository.Delete(nodeId);
                if (flag > 0)
                {
                    NodeEvent ev = new NodeEvent
                    {
                        EventType = NodeEventType.Delete,
                        ServerNodeId = nodeId,
                        TriggerTime = DateTime.Now,
                        ServiceName = serviceName,
                    };
                    nodeEventRepository.Add(ev);
                }
            }
        }

        /// <summary>
        /// 心跳
        /// </summary>
        /// <param name="nodeId"></param>
        public void Heartbeat(long nodeId)
        {
            var flag = serverNodeRepository.Heartbeat(nodeId);
        }

        /// <summary>
        /// 断开连接
        /// </summary>
        /// <param name="nodeId"></param>
        public void Logout(long nodeId, string serviceName)
        {
            lock (_lockObj)
            {
                var flag = serverNodeRepository.Logout(nodeId);
                if (flag > 0)
                {
                    NodeEvent ev = new NodeEvent
                    {
                        EventType = NodeEventType.Logout,
                        ServerNodeId = nodeId,
                        TriggerTime = DateTime.Now,
                        ServiceName = serviceName,

                    };
                    nodeEventRepository.Add(ev);
                }
            }
        }

    }
}
